class Class:
    instances_created = 0

    def __init__(self, *args, **kwargs):
        """
        通常用于 初始化 一个新实例，控制这个初始化的过程，是初始化方法
        比如添加一些属性， 做一些额外的操作，
        发生在类实例被创建完以后(__new__)。它是初始化方法
        :param args:
        :param kwargs:
        """
        print(id(self))
        print("__init__ running args:{0} kwargs:{1}".format(args, kwargs))

    def __new__(cls, *args, **kwargs):
        """
        通常用于控制 生成 一个新实例的过程，是构造方法
        负责创建类实例的静态方法，无需使用staticmethod装饰器修饰，且该方法会优先__init__()初始化方法被调用
        必须返回一个类的实例(如果__new__方法返回None，则__init__方法不会被执行)
        并且返回值只能调用父类中的__new__方法，而不能调用毫无关系的类的__new__方法(_new__的返回值正是__init__中self)
        如果返回其他类的实例，则会跳过对 __init__() 方法的调用

        主要是继承一些不可变的class时(比如int, str, tuple)，
        提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass以及实现单例模式

        new init两者的关系：
        通俗来说: 整个类的地盘是由__new__函数"开辟出来的"，而到了__init__内部就只能在这片地盘上"修修补补"了
        :param args:
        :param kwargs:
        """
        print("__new__ running begin args:{0} kwargs:{1}".format(args, kwargs))
        instance = super(Class, cls).__new__(cls)  # python3__new__()不用参数
        instance.number = cls.instances_created
        cls.instances_created += 1
        print(id(instance))
        print("__new__ running end cls.instances_created: {0}".format(cls.instances_created))
        return instance

    def func(self, name):
        self.name = name
        return "test"


# 通过new 实现取绝对值
class PositiveInt(int):
    # 通过init无法实现
    # def __init__(self, value):
    #     super(PositiveInt, self).__init__()  # __init__()中的参数需要依照父类的参数添加。

    def __new__(cls, *args, **kwargs):
        print("__new__ running begin args:{0} kwargs:{1}".format(args, kwargs))
        return super(PositiveInt, cls).__new__(cls, abs(args[0]))


# 通过new 实现单例模式
class Singleton:
    _instance = None

    def __init__(self, *args, **kwargs):
        print("__init__ running begin args:{0} kwargs:{1}".format(args, kwargs))

    def __new__(cls, *args, **kwargs):
        """
        如果类成员__instance没有或者没有赋值
        那么就创建一个对象，并且赋值为这个对象的引用，保证下次调用这个方法时
        能够知道之前已经创建过对象了，这样就保证了只有1个对象
        :param args:
        :param kwargs:
        """
        print("__new__ running begin args:{0} kwargs:{1}".format(args, kwargs))
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls)
            cls._instance.name = args[0]
            cls._instance.age = args[1]
        return cls._instance


# 通过new 实现单例模式(且只在第一次创建时初始化)
class Singleton2:
    _instance = None
    is_first_instance = False

    def __init__(self, *args, **kwargs):
        if not self.is_first_instance:
            self.name = args[0]
            self.age = args[1]
            self.is_first_instance = True

    def __new__(cls, *args, **kwargs):
        """
        如果类成员__instance没有或者没有赋值
        那么就创建一个对象，并且赋值为这个对象的引用，保证下次调用这个方法时
        能够知道之前已经创建过对象了，这样就保证了只有1个对象
        :param args:
        :param kwargs:
        """
        if not cls._instance:
            cls._instance = super(Singleton2, cls).__new__(cls)
        return cls._instance


if __name__ == "__main__":
    cls1 = Class(4, 5, 6, info="information")
    cls2 = Class()
    print(cls1.number, cls1.instances_created)
    print(cls2.number, cls2.instances_created)
    print(id(cls1))
    print(id(cls2))
    print(cls1.func("zhangsan"))  # 不调用这句代码而直接获取name属性会报错
    print(cls1.name)

    p = PositiveInt(-10)
    print(p)

    # 单例测试
    # instance1 = Singleton("zhangsan", 18)
    # instance2 = Singleton("xxx", 19)
    # print(id(instance1))
    # print(id(instance2))
    # instance1.name = "wangwu"
    # print(instance1.name)
    # print(instance2.name)

    # 单例测试
    instance3 = Singleton2("zhangsan", 18)
    instance4 = Singleton2("xxx", 19)
    print(id(instance3))
    print(id(instance4))
    instance3.name = "wangwu"
    print(instance3.name)
    print(instance4.name)
